home *** CD-ROM | disk | FTP | other *** search
/ Amiga Packmags / Source, The - Issue 5 (1993)(Epsilon)[WB].zip / Source, The - Issue 5 (1993)(Epsilon)[WB].adf / Source / Vectors / sirds.lha / unsirds.c < prev   
C/C++ Source or Header  |  1993-04-12  |  15KB  |  432 lines

  1. /*******************************************************************/
  2. /*                                                                 */
  3. /*    unsirds.c        - by Henry Watson -     Mar. 30, 1993      */
  4. /*                                                                 */
  5. /*                                                                 */
  6. /*    This program will take a Single Image Random Dot Stereogram  */
  7. /* as an input image and output the 3-D image hidden within it.    */
  8. /* Each level of depth in the SIRDS will correspond to a gray      */
  9. /* level in the output image (black=far, white=near).              */
  10. /*    For best results the user should specify the number of gray  */
  11. /* levels in the SIRDS image.  This value is limited, however, due */
  12. /* to the large amount of memory required to process many depth    */
  13. /* levels.                                                         */
  14. /*                                                                 */
  15. /* =============================================================== */
  16. /*                                                                 */
  17. /*  To run, do                                                     */
  18. /*  % unsirds <input_image> <output_image> [disparity_levels]      */
  19. /*                                                                 */
  20. /*******************************************************************/
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <hipl_format.h>  /* include HIPS definitions              */
  25. #include <math.h>
  26.  
  27. #define    PIXEL_FORMAT PFBYTE    /* set the pixel format for the HIPS routines */
  28. typedef byte    PIXEL_TYPE;    /* set the pixel type for the program to use */
  29.  
  30. #define NUM_GRAY_LEVELS 256
  31. #define WHITE (PIXEL_TYPE)255
  32. #define BLACK (PIXEL_TYPE)0
  33.  
  34. #define MAXSIZE 256        /* maximum dimension to image array */
  35.                 /* and thus input image as well     */
  36.  
  37. #define IMAGE_OFFSET_PCT 0.30    /* stereo image offset in terms of percent */
  38.  
  39. #define MAXSIRDSWIDTH 332    /* maximum width of final SIRDS image  */
  40.                 /* MAXSIZE * (IMAGE_OFFSET_PCT+1)      */
  41.  
  42. #define DOTHEIGHT 9        /* height of the fusion dots at the page top */
  43.  
  44. #define MAX_DISP_LEVELS 11    /* maximum number of disparity levels */
  45.  
  46. #define DISPARITY_LEVELS 11    /* default number of discrete levels of      */
  47.                 /* disparity.  Ranges from -d/2 to 0 to +d/2 */
  48.                 /* (ie. number of levels of depth)           */
  49.  
  50. #define MAX_ITERATIONS 30    /* maximum number of iterations to perform */
  51.                 /* when trying to get pixels to converge */
  52.  
  53. #define    frame_number 1        /* constant frame number for HIPS routines */
  54.  
  55.  
  56.  
  57.  
  58. /*******************************************************************/
  59. /* main()                                                          */
  60. /*                                                                 */
  61. /*    The sequence of processing steps involves:                   */
  62. /*     - interpreting the command line                             */
  63. /*     - reading the header                                        */
  64. /*     - validating the input size, format, etc.                   */
  65. /*     - reading image frame                                       */
  66. /*     - performing image processing algorithms                    */
  67. /*     - forming the output image                                  */
  68. /*     - writing to file                                           */
  69. /*                                                                 */
  70. /*******************************************************************/
  71.  
  72. void    main( argc, argv )
  73.  
  74. int    argc;
  75. char    **argv;
  76. {
  77.  
  78. char        *input_filename,
  79.         *output_filename;
  80. FILE        *input_fp, *output_fp;
  81. struct header    input_header, output_header;
  82. PIXEL_TYPE    Sirds[MAXSIZE+DOTHEIGHT][MAXSIRDSWIDTH],
  83.         Object[3][MAX_DISP_LEVELS][MAXSIZE][MAXSIZE];
  84. byte        *pixel_ptr;
  85. int        rowmax, colmax,
  86.         row, col,
  87.         changed_flag,
  88.         loopcount=1,
  89.         right_image_start,
  90.         sirdswidth, sirdsheight,
  91.         sirdsrowzero,
  92.         disparity_levels = DISPARITY_LEVELS,
  93.         disparity_offset = -DISPARITY_LEVELS/2,
  94.         disparity, displevel,
  95.         blackcount, dupecount=0, graylevel;
  96.  
  97.    /* INTERPRETING THE COMMAND LINE */
  98.  
  99.    if( (argc<3) || (argc>4) )
  100.    {
  101.       printf("Usage:  %s <input_image> <output_image> [disparity_levels]\n", argv[0]);
  102.       exit(0);
  103.    }
  104.    input_filename = argv[1];            /* name of input file  */
  105.    output_filename = argv[2];           /* name of output file */
  106.  
  107.    /* check if optional parameter 'disparity_levels' was specified */
  108.    if( argc==4 )
  109.    {
  110.       disparity_levels = atoi( argv[3] );
  111.       disparity_offset = disparity_levels/-2;
  112.  
  113.       /* check the range of the parameter given */
  114.       if( (disparity_levels < 2) || (disparity_levels > MAX_DISP_LEVELS) )
  115.       {
  116.          printf("Invalid number of disparity levels specified.\n");
  117.          printf("Value must be in the range:  2 <= disparity_levels <= %d.\n",
  118.             MAX_DISP_LEVELS);
  119.      printf("Default is %d.\n", DISPARITY_LEVELS);
  120.      exit(-1);
  121.       }
  122.    }
  123.  
  124.  
  125.    /* READING THE HEADER */
  126.  
  127.    /* open the file and read header */
  128.    input_fp = hfopenr( input_filename );
  129.    fread_hdr_a( input_fp, &input_header, input_filename );
  130.  
  131.    /* copy image x and y dimensions */
  132.    sirdsheight = input_header.orows;
  133.    sirdswidth = input_header.ocols;
  134.  
  135.  
  136.    /* VALIDATING THE INPUT SIZE, FORMAT, ETC. */
  137.  
  138.    if( input_header.pixel_format != PIXEL_FORMAT )
  139.    {
  140.       printf("This program only handles pixel format %d.\n",PIXEL_FORMAT);
  141.       printf("Program aborted.\n");
  142.       exit(-1);
  143.    }
  144.    else if( sirdsheight>MAXSIZE+DOTHEIGHT || sirdswidth>MAXSIRDSWIDTH )
  145.    {
  146.       printf("Input image too large.  Maximum size is %d X %d.\n",
  147.      MAXSIZE+DOTHEIGHT,MAXSIRDSWIDTH);
  148.       exit(-1);
  149.    }
  150.    else
  151.    {
  152.       printf("%d X %d %s is being read.\n",
  153.      sirdsheight, sirdswidth, input_filename);
  154.    }
  155.  
  156.  
  157.    /* READING IMAGE FRAME */
  158.  
  159.    /* read the image frame into a buffer; */
  160.    /* image is pointed to by input_header.image */
  161.    fread_image( input_fp, &input_header, frame_number, input_filename );
  162.  
  163.    /* reformat the buffer into an array */
  164.    pixel_ptr = input_header.image;
  165.    for( row=0; row < sirdsheight; row++ )
  166.    {
  167.       pixel_ptr = input_header.image + (row*sirdswidth*input_header.sizepix);
  168.       for( col=0; col < sirdswidth; col++ )
  169.      Sirds[row][col] = (PIXEL_TYPE) *pixel_ptr++;
  170.    }
  171.  
  172.  
  173.  
  174.    /* PERFORMING IMAGE PROCESSING ALGORITHM */
  175.  
  176.    /* determine the right stereo image position and the final image size */
  177.  
  178.    sirdsrowzero = DOTHEIGHT;
  179.  
  180.    rowmax = sirdsheight - sirdsrowzero;
  181.    colmax = sirdswidth / (IMAGE_OFFSET_PCT+1) + 1;
  182.  
  183.    right_image_start = sirdswidth - colmax;
  184.  
  185.  
  186.    /* set the object array to all zeros for each disparity level */
  187.  
  188.    for( row=0; row<rowmax; row++ )
  189.       for( col=0; col<colmax; col++ )
  190.      for( displevel=0; displevel<disparity_levels; displevel++ )
  191.          {
  192.         Object[0][displevel][row][col] = (PIXEL_TYPE) 0;
  193.      }
  194.  
  195.  
  196.    /* initialize the object array with all possible pixel matches given */
  197.    /* the number of disparity levels available. */
  198.  
  199.    printf("Initializing Object array.\n");
  200.    for( row=0; row<rowmax; row++ )
  201.    {
  202.  
  203.       for( col=0; col<colmax; col++ )
  204.       {
  205.      /* now check corresponding pixel in right image for a match at */
  206.      /* different disparities (ie. different shift posns left or right) */
  207.          for( displevel=disparity_offset; displevel<=(-disparity_offset);
  208.           displevel++ )
  209.          {
  210.         /* make sure corresponding position is in range */
  211.         if( right_image_start+col+displevel < sirdswidth )
  212.            
  213.            /* see if pixels match... */
  214.            if( Sirds[row+DOTHEIGHT][right_image_start+col+displevel]
  215.                == Sirds[row+DOTHEIGHT][col] )
  216.            {
  217.           Object[0][displevel-disparity_offset][row][col] =
  218.              (PIXEL_TYPE) 1;
  219.            }
  220.      }
  221.       }
  222.    }
  223.  
  224.  
  225.    /* copy Object[0] to Object[1] to start off... */
  226.    for( displevel=0; displevel<disparity_levels; displevel++ )
  227.       for( row=0; row < rowmax; row++ )
  228.          for( col=0; col < colmax; col++ )
  229.             Object[1][displevel][row][col] = Object[0][displevel][row][col];
  230.  
  231.    printf("Converging... \n");
  232.    while( loopcount<=MAX_ITERATIONS )
  233.    {
  234.    int depthpixels[MAX_DISP_LEVELS],
  235.        maxpixelsabove, maxpixelsbelow,
  236.        i, j, rowpos, colpos, dlevel, vote, oldvalue;
  237.  
  238.       /* reset the changed flag so we can tell when a change has occured. */
  239.       /* if a change has not occurred, then we can assume convergence */
  240.       changed_flag = 0;
  241.  
  242.       printf("%d\n",loopcount);
  243.       for( row=0; row < rowmax; row++ )
  244.          for( col=0; col < colmax; col++ )
  245.          {
  246.  
  247.         /* calculate number of white pixels in a 3x3 mask on each level */
  248.             for( displevel=0; displevel<disparity_levels; displevel++ )
  249.         {
  250.            /* reset number of pixels counted on this level */
  251.            depthpixels[displevel] = 0;
  252.  
  253.                /* count the number of 'on' pixels on this level */
  254.            for( i=-1; i<=1; i++ )
  255.               for( j=-1; j<=1; j++ )
  256.               {
  257.              /* new pixel position to check */
  258.                  rowpos = row+i;
  259.                  colpos = col+j;
  260.  
  261.              /* make sure pixel is in range and a neighbor (not self) */
  262.                  if( (rowpos >= 0) && (rowpos < rowmax) &&
  263.                      (colpos >= 0) && (colpos < colmax) &&
  264.                  !(i==0 && j==0) )
  265.              {
  266.                 /* if pixel is 'on' then count it */
  267.                     if( Object[1][displevel][rowpos][colpos]
  268.                             == (PIXEL_TYPE)1 )
  269.                depthpixels[displevel]++;
  270.              }
  271.                   }
  272.             }
  273.  
  274.         /* now cycle through disparity levels for this pixel position */
  275.         /* and determine if it should be suppressed or re-inforced */
  276.             for( displevel=0; displevel<disparity_levels; displevel++ )
  277.             {
  278.  
  279.                /* only thin out white ('on') pixels */
  280.                if( Object[1][displevel][row][col] == (PIXEL_TYPE) 1 )
  281.            {
  282.  
  283.                   /* Ok, here's where the customization starts... */
  284.               /* Look for the depth levels above and below this one that */
  285.               /* have the most pixels 'on' in the masked area.           */
  286.  
  287.               maxpixelsabove = 0;
  288.               maxpixelsbelow = 0;
  289.  
  290.                   for( dlevel=0; dlevel<disparity_levels; dlevel++ )
  291.               {
  292.                      /* update max values when required */
  293.                  if( depthpixels[dlevel] > maxpixelsabove
  294.                  && dlevel > displevel )
  295.                  {
  296.                 maxpixelsabove = depthpixels[dlevel];
  297.                  }
  298.                  else if( depthpixels[dlevel] > maxpixelsbelow
  299.                               && dlevel < displevel )
  300.                  {
  301.                    maxpixelsbelow = depthpixels[dlevel];
  302.                  }
  303.               }
  304.  
  305.                   /* compute votes from neighbors */
  306.               /* neighbors with same disparity re-inforce pixel */
  307.               /* neighbors with different disparity suppress pixel */
  308.               vote = 2 * depthpixels[displevel]    /* re-inforcement */
  309.                      - maxpixelsabove        /* suppression */
  310.                  - maxpixelsbelow;        /* suppression */
  311.                       /* + Object[0][displevel][row][col] (original value) */
  312.                  
  313.               /* save the pixel's old value */
  314.               oldvalue = Object[2][displevel][row][col];
  315.  
  316.                   /* determine pixel's new value to be on or off */
  317.                   Object[2][displevel][row][col] = (PIXEL_TYPE)
  318.                  ( (vote >= 1) ? 1 : 0 );
  319.            
  320.               /* set changed flag if there was a change */
  321.               if( Object[2][displevel][row][col] != oldvalue )
  322.              changed_flag = 1;
  323.            }
  324.            else
  325.            {
  326.               /* pixel was off so leave it off */
  327.                   Object[2][displevel][row][col] = (PIXEL_TYPE) 0; 
  328.            }
  329.             } /* end for loop through each depth level */
  330.          } /* end for loop through each pixel */
  331.  
  332.  
  333.       /* if changed flag not set then it has converged! so break out of loop */
  334.       if( !changed_flag )
  335.       {
  336.          printf("Convergence!\n");
  337.          break;
  338.       }
  339.  
  340.       /* copy Object[2] to Object[1] to re-iterate... */
  341.       for( displevel=0; displevel<disparity_levels; displevel++ )
  342.          for( row=0; row < rowmax; row++ )
  343.             for( col=0; col < colmax; col++ )
  344.                Object[1][displevel][row][col] = Object[2][displevel][row][col];
  345.  
  346.       loopcount++;
  347.    } /* end while */
  348.  
  349.  
  350.    /* FORMING THE OUTPUT IMAGES */
  351.  
  352.    /* initialize a header from scratch and allocate an image for the header */
  353.  
  354.    init_hdr_alloc( &output_header, "", "", frame_number, "", rowmax, colmax,
  355.                    PIXEL_FORMAT, 1, "" );
  356.  
  357.    /*  output_header - address of the HIPS header                            */
  358.    /*  ""            - original sequence name for documentation purposes     */
  359.    /*  ""            - new sequence name for documentation purpose           */
  360.    /*  frame_number  - only one frame is required here                       */
  361.    /*  ""            - date for documentation purposes                       */
  362.    /*  rowmax        - number of rows                                        */
  363.    /*  colmax        - number of columns                                     */
  364.    /*  PIXEL_FORMAT  - code for pixel format                                 */
  365.    /*  1             - number of color planes                                */
  366.    /*  ""            - the sequence description for documentation purpose    */
  367.  
  368.    /* write out image levels to output image with corresponding gray levels */
  369.    /* - initialize the output image on the first pass */
  370.    /* - produce summary on last pass */
  371.    printf("Forming output image.\n");
  372.    for( displevel=-1; displevel<=disparity_levels; displevel++ )
  373.    {
  374.  
  375.       /* set the pixel_ptr to the image start */
  376.       pixel_ptr = output_header.image;
  377.  
  378.       /* set the graylevel according to disparity level */
  379.       graylevel = (NUM_GRAY_LEVELS-1) -
  380.                   (NUM_GRAY_LEVELS-1)/(disparity_levels-1) * (displevel);
  381.       if( graylevel == 0 ) graylevel = 1; /* avoid messing up 'blackcount' */
  382.  
  383.       if( displevel == -1 )
  384.       {
  385.      /* initialize the image to all black */
  386.          for( row=0; row < rowmax; row++ )
  387.             for( col=0; col < colmax; col++ )
  388.            *pixel_ptr++ = (byte) BLACK;
  389.       }
  390.       else if( displevel == disparity_levels )
  391.       {
  392.      /* count all black pixels (pixels unaccounted for) */
  393.      blackcount =0;
  394.          for( row=0; row < rowmax; row++ )
  395.             for( col=0; col < colmax; col++ )
  396.            if( *pixel_ptr++ == (byte) BLACK )
  397.           blackcount++;
  398.  
  399.      printf("Pixels unaccounted for: %d\n",blackcount);
  400.      printf("Pixels with multiple gray levels: %d\n\n", dupecount);
  401.       }
  402.       else
  403.       {
  404.          /* if pixel at this depth is 'on', then assign the output pixel a */
  405.          /* corresponding gray level */
  406.          for( row=0; row < rowmax; row++ )
  407.             for( col=0; col < colmax; col++ )
  408.            if( Object[2][displevel][row][col] == (PIXEL_TYPE) 1 )
  409.            {
  410.           /* check if pixel is assigned another value */
  411.               if( *pixel_ptr != (byte)BLACK )
  412.              dupecount++;
  413.           /* assign the new pixel value regardless */
  414.               *pixel_ptr++ = (byte)graylevel;
  415.            }
  416.            else
  417.            {
  418.               /* do nothing, move to next pixel */
  419.               pixel_ptr++;
  420.            }
  421.       }
  422.    } /* end for */
  423.  
  424.    /* WRITE TO FILE */
  425.  
  426.    printf("%d X %d %s is being written.\n", rowmax, colmax, output_filename);
  427.    output_fp = ffopen( output_filename, "w" );
  428.    fwrite_header( output_fp, &output_header, output_filename );
  429.    fwrite_image( output_fp, &output_header, 1, output_filename );
  430.    fclose( output_fp );
  431. }
  432.